#include    "includes_fw.h"
#include    "lib_retina.h"	
#include	"mmpf_audio_ctl.h"
#include	"mmpf_i2s_ctl.h"
#include    "config_fw.h"
#include    "mmp_reg_audio.h"
#if (CHIP == P_V2)||(CHIP == VSN_V2)
#include "mmpf_pll.h"
#endif

//------------------------------------------------------------------------------
//  Function    : MMPF_SetI2SFreq
//  Parameter   :
//          freq--sampling rate
//  Return Value : None
//  Description : Set i2s mclk
//------------------------------------------------------------------------------

/** @addtogroup MMPF_I2S
@{
*/
#if SUPPORT_UAC

void MMPF_I2S_CalculateMNValue(u_int MCLK, MMP_USHORT fs, MMP_USHORT *MN, MMP_UBYTE *div)
{
 u_int tmp;
 u_int b256fs;
 u_int i;
 u_int i2s_clk_div;
 u_int up_MCLK;
 u_int low_MCLK;
 u_int m_part;
 u_int n_part;
 
 #if CODEC_VT1602
 MCLK=MCLK/2;
 #endif
 
 b256fs = 256*fs;

 for(i=65;i>=1;i--){
  if( (MCLK/i) > b256fs){
   up_MCLK = MCLK/i;
   low_MCLK = MCLK/(i+1);
   i2s_clk_div = i;
   break;
  }
 }

 tmp = MCLK*10/fs;
 if( (tmp%10) >= 5 ){
  tmp /= 10;
  tmp ++;
 }
 else{
  tmp /= 10;
 }
 
 #if CODEC_VT1602
 	m_part = tmp - 512*i2s_clk_div;
 	n_part = 512 - m_part; 
 #else
 	m_part = tmp - 256*i2s_clk_div;
 	n_part = 256 - m_part;  
 #endif
 
 *MN=(u_short)(m_part*0x100)|((u_short)(n_part));
 *div=i2s_clk_div;
}


void MMPF_SetI2SFreq(MMP_LONG freq)
{
    AITPS_AUD   pAUD    = AITC_BASE_AUD; 
    #if (AUDEXT_DAC != WM8973)
	MMP_USHORT mn_value;
	MMP_UBYTE cur_div;
    #endif
	MMP_ULONG audClk;
    
    #if PCAM_EN==0
    MMPF_PLL_GetGroupFreq(5, &audClk);
    if (pGBL->GBL_CLK_AUD_DIV)
        audClk = audClk/pGBL->GBL_CLK_AUD_DIV;
    clkDiv = (MMP_UBYTE)((audClk * 1000)/(256 * freq));
    ratioM = (MMP_UBYTE)((audClk * 1000)/freq - clkDiv * 256);
    ratioN = 256 - ratioM;

    pAUD->I2S_CLK_DIV = clkDiv;
    pAUD->I2S_RATIO_N_M = ratioM << 8 | ratioN;
    
    #else //Gason
    RTNA_DBG_Str(0, "SETTING I2S MCLK................................\r\n");

    MMPF_PLL_GetGroupFreq(0, &audClk);
    
    audClk >>= 1;
    dbg_printf(3, "audio clock = %d\r\n", audClk);
        
    //wilson: temp solution for da7211
    #if (AUDEXT_DAC == WM8973)
    {
    	MMP_USHORT /*mn_value,*/ ratioM, ratioN;
		MMP_UBYTE clkDiv;

		freq = 48000; //12M/256

	    RTNA_DBG_PrintLong(0, audClk);
	    clkDiv = (MMP_UBYTE)((audClk * 1000)/(256 * freq));
	    ratioM = (MMP_UBYTE)((audClk * 1000)/freq - clkDiv * 256);
	    ratioN = 256 - ratioM;

		pAUD->I2S_MCLK_FIXMODE = 0;
	    pAUD->I2S_CLK_DIV = clkDiv;
	    pAUD->I2S_RATIO_N_M = ratioM << 8 | ratioN;
	    
	    RTNA_DBG_PrintByte(0, pAUD->I2S_CLK_DIV);
	    RTNA_DBG_PrintLong(0, pAUD->I2S_RATIO_N_M);
	}
	#else
	MMPF_I2S_CalculateMNValue(audClk, freq, &mn_value, &cur_div);	
    
	pAUD->I2S_CLK_DIV =  audClk/12000;  //6;//cur_div;//5;//2;  // 24MHz / 12MHz = 2
	
	RTNA_DBG_Str(0, "cur_div = ");
	RTNA_DBG_Byte(0, cur_div);
	RTNA_DBG_Str(0, "\r\n");
    
    pAUD->I2S_MCLK_FIXMODE = 1;
    
	pAUD->I2S_RATIO_N_M = 0xdc24;//mn_value;//0xDC24;
	RTNA_DBG_Str(0, "mn_value = ");
	RTNA_DBG_Short(0, mn_value);
	RTNA_DBG_Str(0, "\r\n");
	#endif
    #endif

	return;
}
//------------------------------------------------------------------------------
//  Function    : MMPF_SetI2SMode
//  Parameter   :
//          i2s_mode--
//          lrck_mode--
//          output_bits--
//  Return Value : None
//  Description : Set i2s interface format
//------------------------------------------------------------------------------
void	MMPF_SetI2SMode(MMP_USHORT i2s_mode, MMP_USHORT lrck_mode, MMP_USHORT output_bits)
{
    AITPS_AUD   pAUD    = AITC_BASE_AUD;

	#if (I2S_OUT_EN == 1) //wilson: for VSN_V3
	pAUD->I2S_OUT_MODE_CTL = i2s_mode;
    #endif

	pAUD->I2S_LRCK_POL = lrck_mode;
	pAUD->I2S_BIT_CLT = output_bits;
}
//------------------------------------------------------------------------------
//  Function    : MMPF_PresetI2S
//  Parameter   :
//          direction--specify i2s in or out
//          mode--specify master or slave mode
//  Return Value : None
//  Description : Set i2s data direction
//------------------------------------------------------------------------------
void	MMPF_PresetI2S(MMP_USHORT direction,MMP_USHORT mode,MMP_USHORT alignment)
{
    AITPS_AUD   pAUD    = AITC_BASE_AUD;
	#if defined(I2S_SWITCH_1DOT8_MODE) 					
    AITPS_GBL   pGBL = AITC_BASE_GBL;
#endif    

	pAUD->I2S_MCLK_CTL = I2S_256_FS;

	pAUD->I2S_MODE_CTL = (mode | I2S_MCLK_OUT_EN);

#if defined(I2S_SWITCH_1DOT8_MODE) 					
    pGBL->GBL_HOST_CTL |=(0x80); 
#endif

    switch (direction) {
    #if (I2S_OUT_EN == 1) //wilson: for VSN_V3
    case I2S_OUT:
        pAUD->I2S_BIT_ALIGN_OUT = (pAUD->I2S_BIT_ALIGN_OUT &0xFF00) | alignment;
        pAUD->I2S_DATA_OUT_EN = 1;
        pAUD->I2S_CTL = (I2S_SDO_OUT_EN | I2S_LRCK_OUT_EN | I2S_BCK_OUT_EN | I2S_HCK_CLK_EN);
        break;
    #endif
    case I2S_IN:
    #if PCAM_EN==0
        pAUD->I2S_BIT_ALIGN_IN = (pAUD->I2S_BIT_ALIGN_OUT &0xFF00) | alignment;
        pAUD->I2S_DATA_IN_SEL = I2S_SDI_IN;
        #if (I2S_OUT_EN == 1) //wilson: for VSN_V3
        pAUD->I2S_DATA_OUT_EN = 0;
        #endif
        pAUD->I2S_CTL = (I2S_SDO_OUT_EN | I2S_LRCK_OUT_EN | I2S_BCK_OUT_EN | I2S_HCK_CLK_EN);//enable sdo,lrck,bck,hck
    #else
        pAUD->I2S_BIT_ALIGN_IN = alignment;
        pAUD->I2S_DATA_IN_SEL = I2S_SDI_IN;				
        #if (I2S_OUT_EN == 1) //wilson: for VSN_V3
        pAUD->I2S_DATA_OUT_EN = 0;
        #endif
        pAUD->I2S_CTL = (I2S_HCK_CLK_EN);//enable hck
    #endif
        break;
    }
}
//------------------------------------------------------------------------------
//  Function    : MMPF_CloseI2S
//  Parameter   : None
//  Return Value : None
//  Description : Disable i2s
//------------------------------------------------------------------------------
void	MMPF_CloseI2S(void)
{
	AITPS_AUD   pAUD    = AITC_BASE_AUD;
	
	pAUD->I2S_CTL = I2S_ALL_DIS;
}
#endif

/** @} */ // end of MMPF_I2S
